// avcodec_sample.0.4.9.cpp
// A small sample program that shows how to use libavformat and libavcodec to
// read video from a file.
//
// This version is for the 0.4.9-pre1 release of ffmpeg. This release adds the
// av_read_frame() API call, which simplifies the reading of video frames
// considerably.
//

#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
#include <stdio.h>

#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#include "wx/ffile.h"
#endif


void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{
    // Open file
    wxString fileName;
    fileName.Printf(_T("framex%d.ppm"), iFrame);

    wxFFile *pFile = new wxFFile(fileName, _T("wb"));
    if (!pFile->IsOpened())
        return;
	
    // Write header
    wxString header;
    header.Printf(_T("P6\n%d %d\n255\n"), width, height);
    pFile->Write(header);
    
    // Write pixel data
    for (int y=0; y<height; ++y)
        pFile->Write(pFrame->data[0] + y * pFrame->linesize[0], width*3);
	
}


bool ConvertToFLV(const wxString &inputFileName, const wxString &outputFileName = wxEmptyString)
{
    // Register all formats and codecs
    av_register_all();

    // Open video file
    AVFormatContext *pFormatCtx;

    if (av_open_input_file(&pFormatCtx, inputFileName.mb_str(), NULL, 0, NULL) != 0)
        return false; // Couldn't open file

    // Retrieve stream information
    if (av_find_stream_info(pFormatCtx) < 0)
        return false; // Couldn't find stream information

    // Dump information about file onto standard error
    dump_format(pFormatCtx, 0, inputFileName.mb_str(), false);


    // Find the first video stream
    int videoStream = -1;

    for (int i=0; i < pFormatCtx->nb_streams; ++i)
    {
        if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
        {
            videoStream = i;
            break;
        }
    }

    if (videoStream == -1)
        return false; // Didn't find a video stream

    // Get a pointer to the codec context for the video stream
    AVCodecContext *pCodecCtx;
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;

    // Find the decoder for the video stream
    AVCodec *pCodec;
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);

    if (pCodec == NULL)
        return false; // Codec not found

    // Open codec
    if (avcodec_open(pCodecCtx, pCodec) < 0)
        return false; // Could not open codec

    // Allocate video frame
    AVFrame *pFrame;
    pFrame = avcodec_alloc_frame();

    // Allocate an AVFrame structure
    AVFrame *pFrameRGB;
    pFrameRGB = avcodec_alloc_frame();

    if (pFrameRGB == NULL)
        return false;

    // Determine required buffer size and allocate buffer
    int numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
    uint8_t *buffer;
    buffer = new uint8_t[numBytes];

    // Assign appropriate parts of buffer to image planes in pFrameRGB
    avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);

    // Read frames and save first five frames to disk
    AVPacket packet;
    int frameFinished;
    int i = 0;

    while (av_read_frame(pFormatCtx, &packet) >= 0)
    {
        // Is this a packet from the video stream?
        if (packet.stream_index == videoStream)
        {
            // Decode video frame
            avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, packet.data, packet.size);

            // Did we get a video frame?
            if (frameFinished)
            {
                // Convert the image from its native format to RGB
                img_convert((AVPicture*)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame,
                            pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);

                // Save the frame to disk
                if (++i < 1000)
                    SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
            }
        }

        // Free the packet that was allocated by av_read_frame
        av_free_packet(&packet);
    }

    // Free the RGB image
    delete [] buffer;
    av_free(pFrameRGB);

    // Free the YUV frame
    av_free(pFrame);

    // Close the codec
    avcodec_close(pCodecCtx);

    // Close the video file
    av_close_input_file(pFormatCtx);

    return true;
}
